#include "LaserEmitter.h"

#include "Physics.h"
#include "Time.h"
#include "Camera.h"
#include "AchievementManager.h"
#include "Events\CSGD_EventSystem.h"
using namespace AchievementSystem;

#include "MetalBox.h"
#include "WoodBox.h"
#include "IceBlock.h"
#include "LaserReflector.h"
#include "LaserReceiver.h"

// Constructor
LaserEmitter::LaserEmitter(void)
{
	objectID = "Laser Emitter";

	range = 1000.0f;
	heatValue = 10.0f;
	direction.fX = 0.0f;
	direction.fY = 1.0f;
	renderLine = direction;
	center.fX = (float)hitBox.left + ((hitBox.right - hitBox.left) >> 1);
	center.fY = (float)hitBox.top + ((hitBox.bottom - hitBox.top) >> 1);
	linecastFrequency = 1;
	PoweredOnStart = false;

	checkpointSave = nullptr;
	isPowered = true;
}

// Destructor
LaserEmitter::~LaserEmitter(void)
{
	delete checkpointSave;
}

void LaserEmitter::Update(float deltaTime)
{
	if(isActive == false || isPowered == false)
		return;

	if(Time::GetInstance().TotalFrames() % linecastFrequency == 0)
	{
		LinecastInfo hitInfo;

		center = Physics::GetCenterPoint(hitBox);

		if(Physics::LineCast(hitInfo, range, center, direction, GetObjectID().c_str()))
		{
			string hitObjID = hitInfo.GetObjectHit()->GetObjectID();

			renderLine = hitInfo.point - center;

			if(hitObjID == "Laser Reflector")
			{
				LaserReflector* ref = dynamic_cast<LaserReflector*>(hitInfo.GetObjectHit());

				float reflectRange = range - Vector2DLength(hitInfo.point - center);
				LinecastInfo info;

				GameObject* obj = ref->ReflectLaser(direction, hitInfo.point, reflectRange, info);

				if(obj != nullptr)
				{
					hitInfo = info;
					hitObjID = info.GetObjectHit()->GetObjectID();
				}

			}

			if(hitObjID == "Player")
			{
				CSGD_EventSystem::GetInstance()->SendEvent("KillPlayer", nullptr, nullptr, (void*)this);
				AchievementManager::GetInstance().SendEvent("Kill Player", 1);
				AchievementManager::GetInstance().SendEvent("Killed by Laser", 1);
			}
			else if(hitObjID == "Metal Box")
			{
				MetalBox* box = dynamic_cast<MetalBox*>(hitInfo.GetObjectHit());

				if(box != nullptr)
					box->ApplyHeat(heatValue);
			}
			else if(hitObjID == "Wood Box")
			{
				WoodBox* box = dynamic_cast<WoodBox*>(hitInfo.GetObjectHit());

				if(box != nullptr)
					box->ApplyHeat(heatValue);
			}
			else if(hitObjID == "Ice Block")
			{
				IceBlock* ice = dynamic_cast<IceBlock*>(hitInfo.GetObjectHit());

				if(ice != nullptr)
					ice->ApplyHeat(heatValue);
			}
			else if(hitObjID == "Laser Receiver")
			{
				// Give the laser receiver power.
				LaserReceiver* Receiver = dynamic_cast<LaserReceiver*>(hitInfo.GetObjectHit());
				Receiver->setIsPowered(true);
			}
		}
	}
}
void LaserEmitter::Render(void) const
{
	if(isActive == true && isPowered == true)
	{
		DrawLaser(
			(int)(center.fX - Camera::GetInstance()->OffsetX()),
			(int)(center.fY - Camera::GetInstance()->OffsetY()),
			(int)(center.fX + (int)renderLine.fX - Camera::GetInstance()->OffsetX()),
			(int)(center.fY + (int)renderLine.fY - Camera::GetInstance()->OffsetY()),
			5
			);
	}

	GameObject::Render();
}
void LaserEmitter::HandleCollision(GameObject& other, CollisionInfo& info)
{
	if(info.Side == CollisionSide::TOP && direction.fY > 0)
		other.SetPosY(other.GetPosY() + (info.Overlap.bottom - info.Overlap.top));
	else if(info.Side == CollisionSide::BOTTOM && direction.fY < 0)
		other.SetPosY(other.GetPosY() - (info.Overlap.bottom - info.Overlap.top));

	other.SetHitBox(Physics::UpdateColRect(other.GetHitBox(), (int)other.GetPosX(), (int)other.GetPosY()));
}

void LaserEmitter::ResetToCheckPoint()
{
	if(checkpointSave != nullptr)
	{
		//memcpy((void*)this, (void*)checkpointSave, sizeof(LaserEmitter));
	}
}

// SetRange
//	- Set the maximum range of the laser beam.
void LaserEmitter::SetRange(float range)
{
	this->range = range;
}

// SetHeatValue
//	- Set how hot the laser is. This value is used to apply heat
//	  to objects such as boxes.
void LaserEmitter::SetHeatValue(float heat)
{
	this->heatValue = heat;
}

// SetDirection
//	- Set the direction the laser is facing.
//	- The x and y values should be between 0 and 1.
void LaserEmitter::SetDirection(float x, float y)
{
	this->direction.fX = x;
	this->direction.fY = y;
	this->renderLine = direction;
}

// SetDirection
//	- Set the direction the laser is facing.
//	- The vector should be normalized.
void LaserEmitter::SetDirection(tVector2D direction)
{
	this->direction = direction;
	this->renderLine = direction;
}

// SetLinecastFrequency
//	- Sets how frequent the laser will perform a linecast.
// frequency : the number of frames to skip between linecasts.
void LaserEmitter::SetLinecastFrequency(unsigned int frequency)
{
	linecastFrequency = frequency + 1;
}

// A recursive helper method that renders the laser beam with a jagged effect.
void LaserEmitter::DrawLaser(int x1, int y1, int x2, int y2, int iterations) const
{
	if(iterations > 0)
	{
		int newX = ((x1 + x2) >> 1) + (rand() % 8) - 4;
		int newY = ((y1 + y2) >> 1) + (rand() % 8) - 4;

		DrawLaser(x1, y1, newX, newY, iterations - 1);
		DrawLaser(newX, newY, x2, y2, iterations - 1);
	}
	else
	{
		CSGD_Direct3D::GetInstance()->DrawLine(x1, y1, x2, y2, D3DCOLOR_ARGB(255, 215 + (rand() % 80) - 40, 215 + (rand() % 80) - 40, 0), 5);
	}
}

void LaserEmitter::SetIsPowered(bool power)
{
	isPowered = power;
}

void LaserEmitter::HandleEvent(Event* pEvent)
{
	if(pEvent->GetEventID() == "GeneratorActive")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(false);
				else
					SetIsPowered(true);
				break;
			}
		}
	}
	else if (pEvent->GetEventID() == "GeneratorNotActive")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(true);
				else
					SetIsPowered(false);
				break;
			}
		}
	}
	else if (pEvent->GetEventID() == "MachineFixed")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(true);
				else
					SetIsPowered(false);
				break;
			}
		}
	}
	else if (pEvent->GetEventID() == "MachineBroken")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(false);
				else
					SetIsPowered(true);
				break;
			}
		}
	}
	if (pEvent->GetEventID() == "ButtonActivated")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(true);
				else
					SetIsPowered(false);
				break;
			}
		}
	}
	else if (pEvent->GetEventID() == "ButtonDeactivated")
	{
		vector<string>* tags = getSenderTags(pEvent->GetEventID());
		for(unsigned int i = 0; i < tags->size(); ++i)
		{
			if(((GameObject*)pEvent->GetSender())->GetTag() == (*tags)[i])
			{
				if( PoweredOnStart == false)
					SetIsPowered(false);
				else
					SetIsPowered(true);
				break;
			}
		}
	}
}

void LaserEmitter::SetPoweredOnStart(bool PoweredToStart )
{
	PoweredOnStart = PoweredToStart;
	SetIsPowered( true );
}